'\" t
.\"     Title: ndiff
.\"    Author: [see the "Authors" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
.\"      Date: 08/06/2021
.\"    Manual: User Commands
.\"    Source: Ndiff
.\"  Language: English
.\"
.TH "NDIFF" "1" "08/06/2021" "Ndiff" "User Commands"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.\" http://bugs.debian.org/507673
.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.ie \n(.g .ds Aq \(aq
.el       .ds Aq '
.\" -----------------------------------------------------------------
.\" * set default formatting
.\" -----------------------------------------------------------------
.\" disable hyphenation
.nh
.\" disable justification (adjust text to left margin only)
.ad l
.\" -----------------------------------------------------------------
.\" * MAIN CONTENT STARTS HERE *
.\" -----------------------------------------------------------------
.SH "NAME"
ndiff \- Utility to compare the results of Nmap scans
.SH "SYNOPSIS"
.HP \w'\fBndiff\fR\ 'u
\fBndiff\fR [\fIoptions\fR] {\fIa\&.xml\fR} {\fIb\&.xml\fR}
.SH "DESCRIPTION"
.PP
Ndiff is a tool to aid in the comparison of Nmap scans\&. It takes two Nmap XML output files and prints the differences between them\&. The differences observed are:
.sp
.RS 4
.ie n \{\
\h'-04'\(bu\h'+03'\c
.\}
.el \{\
.sp -1
.IP \(bu 2.3
.\}
Host states (e\&.g\&. up to down)
.RE
.sp
.RS 4
.ie n \{\
\h'-04'\(bu\h'+03'\c
.\}
.el \{\
.sp -1
.IP \(bu 2.3
.\}
Port states (e\&.g\&. open to closed)
.RE
.sp
.RS 4
.ie n \{\
\h'-04'\(bu\h'+03'\c
.\}
.el \{\
.sp -1
.IP \(bu 2.3
.\}
Service versions (from
\fB\-sV\fR)
.RE
.sp
.RS 4
.ie n \{\
\h'-04'\(bu\h'+03'\c
.\}
.el \{\
.sp -1
.IP \(bu 2.3
.\}
OS matches (from
\fB\-O\fR)
.RE
.sp
.RS 4
.ie n \{\
\h'-04'\(bu\h'+03'\c
.\}
.el \{\
.sp -1
.IP \(bu 2.3
.\}
Script output
.RE
.PP
Ndiff, like the standard
\fBdiff\fR
utility, compares two scans at a time\&.
.SH "OPTIONS SUMMARY"
.PP
\fB\-h\fR, \fB\-\-help\fR
.RS 4
Show a help message and exit\&.
.RE
.PP
\fB\-v\fR, \fB\-\-verbose\fR
.RS 4
Include all hosts and ports in the output, not only those that have changed\&.
.RE
.PP
\fB\-\-text\fR
.RS 4
Write output in human\-readable text format\&.
.RE
.PP
\fB\-\-xml\fR
.RS 4
Write output in machine\-readable XML format\&. The document structure is defined in the file
ndiff\&.dtd
included in the distribution\&.
.RE
.PP
Any other arguments are taken to be the names of Nmap XML output files\&. There must be exactly two\&.
.SH "EXAMPLE"
.PP
Let\*(Aqs use Ndiff to compare the output of two Nmap scans that use different options\&. In the first, we\*(Aqll do a fast scan (\fB\-F\fR), which scans fewer ports for speed\&. In the second, we\*(Aqll scan the larger default set of ports, and run an NSE script\&.
.sp
.if n \{\
.RS 4
.\}
.nf
# \fBnmap \-F scanme\&.nmap\&.org \-oX scanme\-1\&.xml\fR
# \fBnmap \-\-script=html\-title scanme\&.nmap\&.org \-oX scanme\-2\&.xml\fR
$ \fBndiff \-v scanme\-1\&.xml scanme\-2\&.xml\fR
\-Nmap 5\&.35DC1 at 2010\-07\-16 12:09
+Nmap 5\&.35DC1 at 2010\-07\-16 12:13

 scanme\&.nmap\&.org (64\&.13\&.134\&.52):
 Host is up\&.
\-Not shown: 95 filtered ports
+Not shown: 993 filtered ports
 PORT      STATE  SERVICE VERSION
 22/tcp    open   ssh
 25/tcp    closed smtp
 53/tcp    open   domain
+70/tcp    closed gopher
 80/tcp    open   http
+|_ html\-title: Go ahead and ScanMe!
 113/tcp   closed auth
+31337/tcp closed Elite
.fi
.if n \{\
.RE
.\}
.PP
Changes are marked by a
\-
or
+
at the beginning of a line\&. We can see from the output that the scan without the
\fB\-F\fR
fast scan option found two additional ports: 70 and 31337\&. The
html\-title
script produced some additional output for port 80\&. From the port counts, we may infer that the fast scan scanned 100 ports (95 filtered, 3 open, and 2 closed), while the normal scan scanned 1000 (993 filtered, 3 open, and 4 closed)\&.
.PP
The
\fB\-v\fR
(or
\fB\-\-verbose\fR) option to Ndiff made it show even the ports that didn\*(Aqt change, like 22 and 25\&. Without
\fB\-v\fR, they would not have been shown\&.
.SH "OUTPUT"
.PP
There are two output modes: text and XML\&. Text output is the default, and can also be selected with the
\fB\-\-text\fR
option\&. Text output resembles a unified diff of Nmap\*(Aqs normal terminal output\&. Each line is preceded by a character indicating whether and how it changed\&.
\-
means that the line was in the first scan but not in the second;
+
means it was in the second but not the first\&. A line that changed is represented by a
\-
line followed by a
+
line\&. Lines that did not change are preceded by a blank space\&.
.PP
Example\ \&1
is an example of text output\&. Here, port 80 on the host photos\-cache\-snc1\&.facebook\&.com gained a service version (lighttpd 1\&.5\&.0)\&. The host at 69\&.63\&.179\&.25 changed its reverse DNS name\&. The host at 69\&.63\&.184\&.145 was completely absent in the first scan but came up in the second\&.
.PP
\fBExample\ \&1.\ \&Ndiff text output\fR
.sp
.if n \{\
.RS 4
.\}
.nf
\-Nmap 4\&.85BETA3 at 2009\-03\-15 11:00
+Nmap 4\&.85BETA4 at 2009\-03\-18 11:00

 photos\-cache\-snc1\&.facebook\&.com (69\&.63\&.178\&.41):
 Host is up\&.
 Not shown: 99 filtered ports
 PORT   STATE SERVICE VERSION
\-80/tcp open  http
+80/tcp open  http    lighttpd 1\&.5\&.0

\-cm\&.out\&.snc1\&.tfbnw\&.net (69\&.63\&.179\&.25):
+mailout\-snc1\&.facebook\&.com (69\&.63\&.179\&.25):
 Host is up\&.
 Not shown: 100 filtered ports

+69\&.63\&.184\&.145:
+Host is up\&.
+Not shown: 98 filtered ports
+PORT    STATE SERVICE  VERSION
+80/tcp  open  http     Apache httpd 1\&.3\&.41\&.fb1
+443/tcp open  ssl/http Apache httpd 1\&.3\&.41\&.fb1
.fi
.if n \{\
.RE
.\}
.PP
XML output, intended to be processed by other programs, is selected with the
\fB\-\-xml\fR
option\&. It is based on Nmap\*(Aqs XML output, with a few additional elements to indicate differences\&. The XML document is enclosed in
\fInmapdiff\fR
and
\fIscandiff\fR
elements\&. Host differences are enclosed in
\fIhostdiff\fR
tags and port differences are enclosed in
\fIportdiff\fR
tags\&. Inside a
\fIhostdiff\fR
or
\fIportdiff\fR,
\fIa\fR
and
\fIb\fR
tags show the state of the host or port in the first scan (\fIa\fR) or the second scan (\fIb\fR)\&.
.PP
Example\ \&2
shows the XML diff of the same scans shown above in
Example\ \&1\&. Notice how port 80 of photos\-cache\-snc1\&.facebook\&.com is enclosed in
\fIportdiff\fR
tags\&. For 69\&.63\&.179\&.25, the old hostname is in
\fIa\fR
tags and the new is in
\fIb\fR\&. For the new host 69\&.63\&.184\&.145, there is a
\fIb\fR
in the
\fIhostdiff\fR
without a corresponding
\fIa\fR, indicating that there was no information for the host in the first scan\&.
.PP
\fBExample\ \&2.\ \&Ndiff XML output\fR
.sp
.if n \{\
.RS 4
.\}
.nf
<?xml version="1\&.0" encoding="UTF\-8"?>
<nmapdiff version="1">
  <scandiff>
    <hostdiff>
      <host>
        <status state="up"/>
        <address addr="69\&.63\&.178\&.41" addrtype="ipv4"/>
        <hostnames>
          <hostname name="photos\-cache\-snc1\&.facebook\&.com"/>
        </hostnames>
        <ports>
          <extraports count="99" state="filtered"/>
          <portdiff>
            <port portid="80" protocol="tcp">
              <state state="open"/>
              <a>
                <service name="http"/>
              </a>
              <b>
                <service name="http" product="lighttpd" version="1\&.5\&.0"/>
              </b>
            </port>
          </portdiff>
        </ports>
      </host>
    </hostdiff>
    <hostdiff>
      <host>
        <status state="up"/>
        <address addr="69\&.63\&.179\&.25" addrtype="ipv4"/>
        <hostnames>
          <a>
            <hostname name="cm\&.out\&.snc1\&.tfbnw\&.net"/>
          </a>
          <b>
            <hostname name="mailout\-snc1\&.facebook\&.com"/>
          </b>
        </hostnames>
        <ports>
          <extraports count="100" state="filtered"/>
        </ports>
      </host>
    </hostdiff>
    <hostdiff>
      <b>
        <host>
          <status state="up"/>
          <address addr="69\&.63\&.184\&.145" addrtype="ipv4"/>
          <ports>
            <extraports count="98" state="filtered"/>
            <port portid="80" protocol="tcp">
              <state state="open"/>
              <service name="http" product="Apache httpd"
                       version="1\&.3\&.41\&.fb1"/>
            </port>
            <port portid="443" protocol="tcp">
              <state state="open"/>
              <service name="http" product="Apache httpd" tunnel="ssl"
                       version="1\&.3\&.41\&.fb1"/>
            </port>
          </ports>
        </host>
      </b>
    </hostdiff>
  </scandiff>
</nmapdiff>
.fi
.if n \{\
.RE
.\}
.SH "PERIODIC DIFFS"
.PP
Using Nmap, Ndiff, cron, and a shell script, it\*(Aqs possible to scan a network daily and get email reports of the state of the network and changes since the previous scan\&.
Example\ \&3
shows the script that ties it together\&.
.PP
\fBExample\ \&3.\ \&Scanning a network periodically with Ndiff and cron\fR
.sp
.if n \{\
.RS 4
.\}
.nf
#!/bin/sh
TARGETS="\fItargets\fR"
OPTIONS="\-v \-T4 \-F \-sV"
date=`date +%F`
cd /root/scans
nmap $OPTIONS $TARGETS \-oA scan\-$date > /dev/null
if [ \-e scan\-prev\&.xml ]; then
        ndiff scan\-prev\&.xml scan\-$date\&.xml > diff\-$date
        echo "*** NDIFF RESULTS ***"
        cat diff\-$date
        echo
fi
echo "*** NMAP RESULTS ***"
cat scan\-$date\&.nmap
ln \-sf scan\-$date\&.xml scan\-prev\&.xml
.fi
.if n \{\
.RE
.\}
.PP
If the script is saved as
/root/scan\-ndiff\&.sh, add the following line to root\*(Aqs crontab:
.sp
.if n \{\
.RS 4
.\}
.nf
0 12 * * * /root/scan\-ndiff\&.sh
.fi
.if n \{\
.RE
.\}
.sp
.SH "EXIT CODE"
.PP
The exit code indicates whether the scans are equal\&.
.sp
.RS 4
.ie n \{\
\h'-04'\(bu\h'+03'\c
.\}
.el \{\
.sp -1
.IP \(bu 2.3
.\}
0 means that the scans are the same in all the aspects Ndiff knows about\&.
.RE
.sp
.RS 4
.ie n \{\
\h'-04'\(bu\h'+03'\c
.\}
.el \{\
.sp -1
.IP \(bu 2.3
.\}
1 means that the scans differ\&.
.RE
.sp
.RS 4
.ie n \{\
\h'-04'\(bu\h'+03'\c
.\}
.el \{\
.sp -1
.IP \(bu 2.3
.\}
2 indicates a runtime error, such as the failure to open a file\&.
.RE
.sp
.SH "BUGS"
.PP
Report bugs to the
nmap\-dev
mailing list at
<dev@nmap\&.org>\&.
.SH "HISTORY"
.PP
Ndiff started as a project by Michael Pattrick during the 2008 Google Summer of Code\&. Michael designed the program and led the discussion of its output formats\&. He wrote versions of the program in Perl and C++, but the summer ended shortly after it was decided to rewrite the program in Python for the sake of Windows (and Zenmap) compatibility\&. This Python version was written by David Fifield\&. James Levine
\m[blue]\fBreleased\fR\m[]\&\s-2\u[1]\d\s+2
a Perl script named Ndiff with similar functionality in 2000\&.
.SH "AUTHORS"
.PP
David Fifield
<david@bamsoftware\&.com>
.PP
Michael Pattrick
<mpattrick@rhinovirus\&.org>
.SH "WEB SITE"
.PP
\m[blue]\fB\%https://nmap.org/ndiff/\fR\m[]
.SH "NOTES"
.IP " 1." 4
released
.RS 4
\%http://seclists.org/nmap-hackers/2000/315
.RE
